package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author atguigu-mqx
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void testLock() {
        //  上锁：
        RLock lock = redissonClient.getLock("lock");
        lock.lock();
        try {
            //  业务逻辑
            String num = redisTemplate.opsForValue().get("num");
            //  判断 === 判断数据以及类型 javaScript
            if (StringUtils.isEmpty(num)){
                return;
            }
            //  存储数据
            int numValue = Integer.parseInt(num);
            //  set(key,value);
            redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
        } finally {
            //  解锁
            lock.unlock();
        }
    }

    @Override
    public String readLock() {
        //  创建一个对写锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        //  上读锁
        rwlock.readLock().lock(10,TimeUnit.SECONDS);
        //  执行业务逻辑
        String msg = this.redisTemplate.opsForValue().get("msg");
        //  返回数据
        return msg;
    }

    @Override
    public String writeLock() {
        //  创建一个对写锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        //  上写锁
        rwlock.writeLock().lock(10,TimeUnit.SECONDS);
        //  执行业务逻辑
        this.redisTemplate.opsForValue().set("msg",UUID.randomUUID().toString());

        return "写入完成....";
    }

    //  使用setnx 分布式锁！
    //    @Override
    //    public void testLock() {
    //        /*
    //        1.  获取缓存中的数据key = num
    //            判断缓存中的数据是否为空！
    //            true:
    //                返回！
    //                null and ""; 啥区别?
    //            false:
    //                将数据+1 ，放入缓存！
    //         */
    //        //  setnx key value;
    //        //  Boolean flag = this.redisTemplate.opsForValue().setIfAbsent("lock", "ok");
    //        //  set k1 v1 ex 30 nx;
    //        String uuid = UUID.randomUUID().toString();
    //        Boolean flag = this.redisTemplate.opsForValue().setIfAbsent("lock", uuid,3,TimeUnit.SECONDS);
    ////        redisTemplate.expire("lock",10, TimeUnit.SECONDS);
    //        //  说明里面没有锁！
    //        if (flag){
    //            String num = redisTemplate.opsForValue().get("num");
    //            //  判断 === 判断数据以及类型 javaScript
    //            if (StringUtils.isEmpty(num)){
    //                return;
    //            }
    //            //  存储数据
    //            int numValue = Integer.parseInt(num);
    //            //  set(key,value);
    //            redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
    //            //  判断是否是属于自己的uuid
    //            //  if (uuid.equals(redisTemplate.opsForValue().get("lock"))){
    //                //  index1 到这了。
    //                //  del 释放锁！
    //                //  redisTemplate.delete("lock");
    //            //  }
    //            //  使用lua 脚本删除！
    //            //  准备一个lua 脚本！
    //            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    //
    //            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
    //            //  存储lua 脚本
    //            redisScript.setScriptText(script);
    //            redisScript.setResultType(Long.class);
    //            this.redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);
    //
    //        }else {
    //            //  等待
    //            try {
    //                Thread.sleep(200);
    //            } catch (InterruptedException e) {
    //                e.printStackTrace();
    //            }
    //            //  自旋
    //            testLock();
    //        }
    //
    //    }
}
